
package com.tianya.utils;

import okhttp3.*;
import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;

public class HttpUtil {

    private static final ConcurrentHashMap<String, OkHttpClient> clientCache = new ConcurrentHashMap<>();

    /**
     * 根据指定的连接超时和读取超时时间获取一个具有相应超时设置的OkHttpClient实例。
     * 这个方法通过缓存机制来避免重复创建具有相同超时设置的OkHttpClient实例，从而优化性能。
     *
     * @param connectTimeout 连接超时时间，单位为毫秒。
     * @param readTimeout 读取超时时间，单位为毫秒。
     * @return 具有指定超时设置的OkHttpClient实例。
     */
    private static OkHttpClient getClientWithTimeout(long connectTimeout, long readTimeout) {
        // 使用连接超时和读取超时时间的组合作为缓存键。
        String key = connectTimeout + "," + readTimeout;
        // 如果缓存中不存在对应的OkHttpClient实例，则通过computeIfAbsent方法创建一个新的实例并存入缓存。
        return clientCache.computeIfAbsent(key, k -> {
            // 创建一个新的OkHttpClient.Builder实例，并设置连接超时和读取超时时间。
            OkHttpClient.Builder builder = new OkHttpClient.Builder()
                    .connectTimeout(connectTimeout, TimeUnit.MILLISECONDS)
                    .readTimeout(readTimeout, TimeUnit.MILLISECONDS);
            // 根据Builder构建并返回OkHttpClient实例。
            return builder.build();
        });
    }

    /**
     * 发起HTTP POST请求，参数为JSON字符串，支持自定义超时时间设置。
     * @param url 请求的URL地址
     * @param jsonString JSON格式的参数
     * @param connectTimeout 连接超时时间，单位：毫秒
     * @param readTimeout 读取超时时间，单位：毫秒
     * @return 响应体中的字符串数据
     * @throws IOException 网络请求异常
     */
    public static String doPost(String url, String jsonString, long connectTimeout, long readTimeout) throws IOException {
        OkHttpClient client = getClientWithTimeout(connectTimeout, readTimeout);

        MediaType mediaType = MediaType.parse("application/json; charset=utf-8");
        RequestBody requestBody = RequestBody.create(mediaType, jsonString);

        Request request = new Request.Builder()
                .url(url)
                .post(requestBody)
                .build();

        try (Response response = client.newCall(request).execute()) {
            if (!response.isSuccessful()) {
                throw new IOException("Unexpected code " + response);
            }
            return response.body().string();
        }
    }

    /**
     * 执行HTTP GET请求，支持参数附加到URL。
     *
     * @param url       请求的基本URL
     * @param params    请求参数，Map类型，键值对形式
     * @param connectTimeout 连接超时时间，单位：毫秒
     * @param readTimeout 读取超时时间，单位：毫秒
     * @return 响应体中的字符串数据
     * @throws IOException 网络请求异常
     */
    public static String doGetWithParams(String url, Map<String, String> params, long connectTimeout, long readTimeout) throws IOException {
        OkHttpClient client = getClientWithTimeout(connectTimeout, readTimeout);

        StringBuilder urlBuilder = new StringBuilder(url);
        if (params != null && !params.isEmpty()) {
            urlBuilder.append("?");
            for (Map.Entry<String, String> entry : params.entrySet()) {
                String encodedKey = URLEncoder.encode(entry.getKey(), StandardCharsets.UTF_8.toString());
                String encodedValue = URLEncoder.encode(entry.getValue(), StandardCharsets.UTF_8.toString());
                urlBuilder.append(encodedKey).append("=").append(encodedValue).append("&");
            }
            // 移除最后一个多余的"&"
            urlBuilder.deleteCharAt(urlBuilder.length() - 1);
        }

        Request request = new Request.Builder()
                .url(urlBuilder.toString())
                .get()
                .build();

        try (Response response = client.newCall(request).execute()) {
            if (!response.isSuccessful()) {
                throw new IOException("Unexpected code " + response);
            }
            ResponseBody responseBody = response.body();
            if (responseBody != null) {
                return responseBody.string();
            } else {
                throw new IOException("Response body is null");
            }
        }
    }
}